package com.xyyl.patient.controller;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayBaseRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xyyl.patient.common.utils.SysConfigUtils;
import com.xyyl.patient.core.constant.AppEnum;
import com.xyyl.patient.core.controller.BaseController;
import com.xyyl.patient.core.util.DateUtils;
import com.xyyl.patient.core.util.ResponseBodyResult;
import com.xyyl.patient.core.util.RestClient;
import com.xyyl.patient.entity.base.NotificationEntity;
import com.xyyl.patient.entity.order.PhoneOrder;
import com.xyyl.patient.service.doctor.DoctorService;
import com.xyyl.patient.service.order.PhoneOrderService;
import com.xyyl.patient.service.user.UserService;
import com.xyyl.patient.vo.user.UserVo;

/**
 * @projectName:xyyl-patient-web
 * @ClassName: PhoneOrderPayController
 * @Description: 电话咨询订单Controller
 * @author chens
 * @date 2017年9月26日
 *
 */
@RestController
@RequestMapping("/phoneOrder")
public class PhoneOrderPayController extends BaseController {

	private Logger logger = LogManager.getLogger(PhoneOrderPayController.class);

	@Autowired
	private PhoneOrderService consultOrderService;

	@Autowired
	private DoctorService doctorService;

	@Autowired
	private UserService userService;

	@Autowired
	private WxPayService payService;

	@Value("#{weixin['common.domain']}")
	private String domain;

	/**
	 * @Title: submitOrder
	 * @Description: 提交订单 
	 * @param @param consultOrder
	 * @param @return    参数
	 * @return JSONObject    返回类型
	 * @throws
	 */
	@RequestMapping(value = "/submitOrder", method = RequestMethod.POST)
	public JSONObject submitOrder(@RequestBody PhoneOrder consultOrder) {

		logger.info("---submit  phoneOrder---");

		try {
			if (consultOrder != null) {
				consultOrder.setStatus(AppEnum.common.Pay_status_not.getValue());
			}
			return ResponseBodyResult.success("下单成功", consultOrderService.insertConsultOrder(consultOrder));

		} catch (Exception e) {
			return ResponseBodyResult.error("下单失败", e);
		}
	}

	/**
	 * @Title: queryOrderDetailById
	 * @Description: 订单明细查询
	 * @param @param id
	 * @param @return    参数
	 * @return JSONObject    返回类型
	 * @throws
	 */
	@RequestMapping(value = "/queryOrderDetailById", method = RequestMethod.GET)
	public JSONObject queryOrderDetailById(@RequestParam Integer id) {

		logger.info(" query order:{}", id);
		try {
			return ResponseBodyResult.success(consultOrderService.queryOrderDetailById(id));
		} catch (Exception e) {
			return ResponseBodyResult.error("订单明细查询失败!", e);
		}
	}

	/**
	 * @Title: confirmPay
	 * @Description: 确认支付 
	 * 一、余额支付： 1.直接扣款即可，并更新订单
	 * 二、微信支付：1.调用微信统一下单接口，返回JSSDKPayInfo相关的信息 
	 * @param @param consultOrder
	 * @param @return    参数
	 * @return JSONObject    返回类型
	 * @throws
	 */
	@RequestMapping(value = "/confirmPay", method = RequestMethod.POST)
	public JSONObject confirmPay(@RequestBody PhoneOrder consultOrder) {

		logger.info("---confirmPay  payOrder---");

		Integer payType = consultOrder.getPayType();
		BigDecimal orderAmout = consultOrder.getPrice();
		try {
			PhoneOrder consultOrderVo = consultOrderService.queryOrderDetailById(consultOrder.getId());
			if (consultOrderVo.getStatus().equals(AppEnum.common.Pay_status_confirm.getValue())) {
				return ResponseBodyResult.fail("该订单已支付，请勿重复提交!");
			}

			if (payType.equals(AppEnum.common.Order_payType_account.getValue())) {

				/** 查询账户信息 **/
				UserVo userVo = userService.queryUserDetailById(consultOrder.getUserid());
				BigDecimal totalFee = userVo.getAccountbalance();

				if (totalFee.compareTo(orderAmout) < 0) {
					return ResponseBodyResult.fail("支付失败!,账户余额不足!");
				} else {
					consultOrderService.updateConsultOrder(consultOrder);
					return ResponseBodyResult.success("支付成功!", "SUCCESS");
				}

			}

			return submitWxPay(consultOrder);

		} catch (Exception e) {

			return ResponseBodyResult.error("订单提交失败!", e);
		}
	}

	/**
	 * @Title: submitWxPay
	 * @Description:提交微信统一下单
	 * @param @param consultOrder
	 * @param @return    参数
	 * @return JSONObject    返回类型
	 * @throws
	 */
	private JSONObject submitWxPay(PhoneOrder consultOrder) {
		/** 组装参数信息 **/
		WxPayUnifiedOrderRequest prepayInfo = WxPayUnifiedOrderRequest.newBuilder().openid(consultOrder.getOpenid())
				.outTradeNo(consultOrder.getOrdersn())
				.totalFee(WxPayBaseRequest.yuanToFee(String.valueOf(consultOrder.getPrice())))
				.body(consultOrder.getOrderDetail()).spbillCreateIp("192.168.0.1")
				.notifyURL(domain + "/phoneOrder/orderPayCallback").build();

		/** 提交微信统一下单 **/
		Map<String, String> payInfos = Maps.newHashMap();
		try {
			payInfos = this.payService.getPayInfo(prepayInfo);
			if (payInfos != null && payInfos.get("package") != null) {
				return ResponseBodyResult.success("提交成功", payInfos);
			} else {
				return ResponseBodyResult.fail("统一下单失败");
			}
		} catch (WxPayException e) {
			return ResponseBodyResult.error("统一下单失败", e);
		}

	}

	/**
	 * @Title: orderPayCallback
	 * @Description: 微信通知支付结果的回调并更新订单信息
	 * @param rechargeOrder
	 * @return String 返回类型
	 * @throws
	 */
	@RequestMapping(value = "/orderPayCallback", method = RequestMethod.POST)
	public String orderPayCallback(HttpServletRequest request, HttpServletResponse response) {

		logger.info("---callback  payOrder---");

		try {
			synchronized (this) {
				/** 解析支付结果 **/
				String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
				WxPayOrderNotifyResult result = payService.parseOrderNotifyResult(xmlResult);
				if (AppEnum.common.Pay_result_success.getName().equals(result.getReturnCode())) {
					if (AppEnum.common.Pay_result_success.getName().equals(result.getResultCode())) {

						/** 支付成功，处理业务数据 **/
						String orderId = result.getOutTradeNo();
						String ordersn = result.getTransactionId();
						String openid = result.getOpenid();
						PhoneOrder consultOrder = consultOrderService.queryOrderDetailBySn(openid, orderId);
						if (consultOrder.getStatus().equals(AppEnum.common.Pay_status_not.getValue())) {
							consultOrder.setStatus(AppEnum.common.Pay_status_confirm.getValue());
							consultOrder.setPayordersn(ordersn);
							consultOrder.setPayType(AppEnum.common.Order_payType_wx.getValue());
							consultOrderService.updateConsultOrder(consultOrder);
							
							
							//发送短信通知
							sendMessage(consultOrder.getDoctorid());
						}

						return WxPayNotifyResponse.success("ok");
					} else {
						return WxPayNotifyResponse.fail("result_code is FAIL");
					}
				} else {
					return WxPayNotifyResponse.fail("check signature FAIL");
				}

			}
		} catch (Exception e) {
			return WxPayNotifyResponse.fail("http request FAIL");
		}

	}

	/**
	 * @Title: orderRefundNotify
	 * @Description: 退款通知【微信調用】
	 * @param @param request
	 * @param @param response
	 * @param @return    参数
	 * @return String    返回类型
	 * @throws
	 */
	@RequestMapping(value = "/orderRefundNotify", method = RequestMethod.POST)
	public String orderRefundNotify(HttpServletRequest request, HttpServletResponse response) {

		logger.info("---callback  refunNotify---");
		try {
			synchronized (this) {
				String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
				if (xmlResult != null) {
					WxPayRefundNotifyResult result = payService.parseRefundNotifyResult(xmlResult);
					if (AppEnum.common.Pay_result_success.getName().equals(result.getReturnCode())) {
						if (AppEnum.common.Pay_result_success.getName().equals(result.getReqInfo().getRefundStatus())) {

							String ordersn = result.getReqInfo().getOutTradeNo();
							PhoneOrder consultOrder = consultOrderService.queryOrderDetailBySn(null, ordersn);

							/** 未处理的退款通知提交给后台处理 **/
							if (consultOrder.getStatus().equals(AppEnum.common.Prder_status_refund_wating.getValue())) {
								String refun_api_url = SysConfigUtils
										.getConfigValue(AppEnum.sysConfig.OMS_SYSTEM_PAY_NOTITY_API_URL.name());
								return RestClient.postForObject(refun_api_url, JSON.toJSONString(result), String.class);
							}
							return WxPayNotifyResponse.success("ok");
						} else {
							return WxPayNotifyResponse.fail("result_code is FAIL");
						}
					} else {
						return WxPayNotifyResponse.fail("check signature FAIL");
					}
				}

				return null;
			}
		} catch (Exception e) {
			return WxPayNotifyResponse.fail("http request FAIL");
		}

	}

	/**
	 * @Title: getBookTimeListByDoctorId
	 * @Description: 根据医生id获取预定时间列表
	 * @param @param id
	 * @param @return    参数
	 * @return JSONObject    返回类型
	 * @throws
	 */
	@RequestMapping(value = "/getBookTimeListByDoctorId", method = RequestMethod.GET)
	public JSONObject getBookTimeListByDoctorId(@RequestParam Integer id) {

		logger.info(" doctor id:{}", id);
		List<Map<String, Object>> bookTimes = null;
		List<Map<String, Object>> resutMaps = Lists.newLinkedList();
		try {
			bookTimes = doctorService.getBookTimeByDoctorId(id);
			if (bookTimes != null) {

				// 1.未来7天对应的周几：[{3：2017-09-27},{4：2017-09-28}，{5：2017-09-29},{6,2017-09-30}]
				Map<Integer, String> weekData = Maps.newHashMap();
				for (int i = 0; i < 7; i++) {
					String day = null;
					if (i == 0) {
						day = DateUtils.currentDate();
					} else {
						day = DateUtils.addDay(new Date(), i);
					}
					Calendar cal = Calendar.getInstance();
					Date datet = DateUtils.parseDatetime(day, "yyyy-MM-dd");
					cal.setTime(datet);
					// 指示一个星期中的某天。
					int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
					if (w < 0) {
						w = 0;
					}
					weekData.put(w, day);
				}

				// 遍历赋值
				for (Map<String, Object> map : bookTimes) {
					Integer weekDay = Integer.valueOf(String.valueOf(map.get("bookdate")));
					String booktime = String.valueOf(map.get("booktime"));
					for (Integer dataKey : weekData.keySet()) {
						Integer key = dataKey;
						if (weekDay.equals(key)) {
							Map<String, Object> dataMap = Maps.newHashMap();
							String day = weekData.get(key);
							dataMap.put("date", day);
							dataMap.put("time", booktime);
							resutMaps.add(dataMap);
							break;
						}
					}
				}
				if (!resutMaps.isEmpty()) {
					Collections.sort(resutMaps, new Comparator<Map<String, Object>>() {
						@Override
						public int compare(Map<String, Object> o1, Map<String, Object> o2) {
							Long time1 = DateUtils.parseDate(String.valueOf(o1.get("date"))).getTime();
							Long time2 = DateUtils.parseDate(String.valueOf(o2.get("date"))).getTime();
							return time1.compareTo(time2);
						}
					});
				}

			}
			return ResponseBodyResult.success(resutMaps);
		} catch (Exception e) {
			return ResponseBodyResult.error("查询预定时间失败!", e);
		}
	}

	/**
	 * @Title: sendMessage
	 * @Description: 電話预约成功，向APP端推送消息
	 * @param @param doctorid    参数
	 * @return void    返回类型
	 * @throws
	 */
	public void sendMessage(Integer doctorid) {

		logger.info("--- push message---");

		NotificationEntity notificationEntity = null;
		try {
			String deviceTokens = doctorService.getDoctorDeviceTokensById(doctorid);
			if (StringUtils.isNotEmpty(deviceTokens)) {

				String activity = SysConfigUtils
						.getConfigValue(AppEnum.sysConfig.OMS_PHONE_ORDER_ANDROID_ACTIVITY.name());
				String push_api_url = SysConfigUtils
						.getConfigValue(AppEnum.sysConfig.OMS_PHONE_ORDER_PUSH_API_URL.name());

				notificationEntity = new NotificationEntity(deviceTokens, "电话咨询订单", "您有一条电话咨询订单，点击查看", activity);
				notificationEntity.setDoctorIds(new Long[] { doctorid.longValue() });
				notificationEntity.setBusinessType(AppEnum.common.Order_consumetype_phone.getValue());

				RestClient.postForObject(push_api_url, JSON.toJSONString(notificationEntity), String.class);
			}
		} catch (Exception e) {
			logger.error("推送失败:" + e);
		}

	}

	/**
	 * @Title: getLastOrderByUserid
	 * @Description: 获取最后一次电话咨询订单信息
	 * @param @param id
	 * @param @return    参数
	 * @return JSONObject    返回类型
	 * @throws
	 */
	@RequestMapping(value = "/getLastOrderByUserid", method = RequestMethod.GET)
	public JSONObject getLastOrderByUserid(@RequestParam Integer id) {

		logger.info(" query order:{}", id);
		try {
			return ResponseBodyResult.success(consultOrderService.getLastOrderByUserid(id));
		} catch (Exception e) {
			return ResponseBodyResult.error("订单明细查询失败!", e);
		}
	}

}
